﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
using HslCommunication.Core.Net;
using HslCommunication.LogNet;

namespace HslCommunication.Enthernet
{
	/// <summary>
	/// 高性能的异步网络服务器类，适合搭建局域网聊天程序，消息推送程序
	/// </summary>
	/// <remarks>
	/// 详细的使用说明，请参照博客<a href="http://www.cnblogs.com/dathlin/p/8097897.html">http://www.cnblogs.com/dathlin/p/8097897.html</a>
	/// </remarks>
	/// <example>
	/// 此处贴上了Demo项目的服务器配置的示例代码
	/// <code lang="cs" source="TestProject\ComplexNetServer\FormServer.cs" region="NetComplexServer" title="NetComplexServer示例" />
	/// </example>
	// Token: 0x020000F1 RID: 241
	public class NetComplexServer : NetworkServerBase
	{
		/// <summary>
		/// 实例化一个网络服务器类对象
		/// </summary>
		// Token: 0x0600146A RID: 5226 RVA: 0x00069C6C File Offset: 0x00067E6C
		public NetComplexServer()
		{
			this.appSessions = new List<AppSession>();
			this.lockSessions = new object();
		}

		/// <summary>
		/// 所支持的同时在线客户端的最大数量，默认为10000个
		/// </summary>
		// Token: 0x170004E6 RID: 1254
		// (get) Token: 0x0600146B RID: 5227 RVA: 0x00069CBE File Offset: 0x00067EBE
		// (set) Token: 0x0600146C RID: 5228 RVA: 0x00069CC6 File Offset: 0x00067EC6
		public int ConnectMax
		{
			get
			{
				return this.connectMaxClient;
			}
			set
			{
				this.connectMaxClient = value;
			}
		}

		/// <summary>
		/// 获取或设置服务器是否记录客户端上下线信息，默认为true
		/// </summary>
		// Token: 0x170004E7 RID: 1255
		// (get) Token: 0x0600146D RID: 5229 RVA: 0x00069CCF File Offset: 0x00067ECF
		// (set) Token: 0x0600146E RID: 5230 RVA: 0x00069CD7 File Offset: 0x00067ED7
		public bool IsSaveLogClientLineChange { get; set; } = true;

		/// <summary>
		/// 所有在线客户端的数量
		/// </summary>
		// Token: 0x170004E8 RID: 1256
		// (get) Token: 0x0600146F RID: 5231 RVA: 0x00069CE0 File Offset: 0x00067EE0
		public int ClientCount
		{
			get
			{
				return this.appSessions.Count;
			}
		}

		/// <summary>
		/// 初始化操作
		/// </summary>
		// Token: 0x06001470 RID: 5232 RVA: 0x00069CED File Offset: 0x00067EED
		protected override void StartInitialization()
		{
			this.Thread_heart_check = new Thread(new ThreadStart(this.ThreadHeartCheck))
			{
				IsBackground = true,
				Priority = ThreadPriority.AboveNormal
			};
			this.Thread_heart_check.Start();
			base.StartInitialization();
		}

		/// <summary>
		/// 关闭网络时的操作
		/// </summary>
		// Token: 0x06001471 RID: 5233 RVA: 0x00069D2C File Offset: 0x00067F2C
		protected override void CloseAction()
		{
			Thread thread_heart_check = this.Thread_heart_check;
			if (thread_heart_check != null)
			{
				thread_heart_check.Abort();
			}
			this.ClientOffline = null;
			this.ClientOnline = null;
			this.AcceptString = null;
			this.AcceptByte = null;
			object obj = this.lockSessions;
			lock (obj)
			{
				this.appSessions.ForEach(delegate(AppSession m)
				{
					Socket workSocket = m.WorkSocket;
					if (workSocket != null)
					{
						workSocket.Close();
					}
				});
			}
			base.CloseAction();
		}

		// Token: 0x06001472 RID: 5234 RVA: 0x00069DCC File Offset: 0x00067FCC
		private void TcpStateUpLine(AppSession session)
		{
			object obj = this.lockSessions;
			lock (obj)
			{
				this.appSessions.Add(session);
			}
			Action<AppSession> clientOnline = this.ClientOnline;
			if (clientOnline != null)
			{
				clientOnline(session);
			}
			Action<int> allClientsStatusChange = this.AllClientsStatusChange;
			if (allClientsStatusChange != null)
			{
				allClientsStatusChange(this.ClientCount);
			}
			bool isSaveLogClientLineChange = this.IsSaveLogClientLineChange;
			if (isSaveLogClientLineChange)
			{
				ILogNet logNet = base.LogNet;
				if (logNet != null)
				{
					logNet.WriteDebug(this.ToString(), string.Format("[{0}] Name:{1} {2}", session.IpEndPoint, (session != null) ? session.LoginAlias : null, StringResources.Language.NetClientOnline));
				}
			}
		}

		// Token: 0x06001473 RID: 5235 RVA: 0x00069E8C File Offset: 0x0006808C
		private void TcpStateDownLine(AppSession session, bool regular, bool logSave = true)
		{
			object obj = this.lockSessions;
			lock (obj)
			{
				bool flag2 = this.appSessions.Remove(session);
				bool flag3 = !flag2;
				if (flag3)
				{
					return;
				}
			}
			Socket workSocket = session.WorkSocket;
			if (workSocket != null)
			{
				workSocket.Close();
			}
			string arg = regular ? StringResources.Language.NetClientOffline : StringResources.Language.NetClientBreak;
			Action<AppSession, string> clientOffline = this.ClientOffline;
			if (clientOffline != null)
			{
				clientOffline(session, arg);
			}
			Action<int> allClientsStatusChange = this.AllClientsStatusChange;
			if (allClientsStatusChange != null)
			{
				allClientsStatusChange(this.ClientCount);
			}
			bool flag4 = this.IsSaveLogClientLineChange && logSave;
			if (flag4)
			{
				ILogNet logNet = base.LogNet;
				if (logNet != null)
				{
					logNet.WriteInfo(this.ToString(), string.Format("[{0}] Name:{1} {2}", session.IpEndPoint, (session != null) ? session.LoginAlias : null, arg));
				}
			}
		}

		/// <summary>
		/// 让客户端正常下线，调用本方法即可自由控制会话客户端强制下线操作。
		/// </summary>
		/// <param name="session">会话对象</param>
		// Token: 0x06001474 RID: 5236 RVA: 0x00069F84 File Offset: 0x00068184
		public void AppSessionRemoteClose(AppSession session)
		{
			this.TcpStateDownLine(session, true, true);
		}

		/// <summary>
		/// 客户端的上下限状态变更时触发，仅作为在线客户端识别
		/// </summary>
		// Token: 0x14000025 RID: 37
		// (add) Token: 0x06001475 RID: 5237 RVA: 0x00069F90 File Offset: 0x00068190
		// (remove) Token: 0x06001476 RID: 5238 RVA: 0x00069FC8 File Offset: 0x000681C8
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event Action<int> AllClientsStatusChange;

		/// <summary>
		/// 当客户端上线的时候，触发此事件
		/// </summary>
		// Token: 0x14000026 RID: 38
		// (add) Token: 0x06001477 RID: 5239 RVA: 0x0006A000 File Offset: 0x00068200
		// (remove) Token: 0x06001478 RID: 5240 RVA: 0x0006A038 File Offset: 0x00068238
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event Action<AppSession> ClientOnline;

		/// <summary>
		/// 当客户端下线的时候，触发此事件
		/// </summary>
		// Token: 0x14000027 RID: 39
		// (add) Token: 0x06001479 RID: 5241 RVA: 0x0006A070 File Offset: 0x00068270
		// (remove) Token: 0x0600147A RID: 5242 RVA: 0x0006A0A8 File Offset: 0x000682A8
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event Action<AppSession, string> ClientOffline;

		/// <summary>
		/// 当接收到文本数据的时候,触发此事件
		/// </summary>
		// Token: 0x14000028 RID: 40
		// (add) Token: 0x0600147B RID: 5243 RVA: 0x0006A0E0 File Offset: 0x000682E0
		// (remove) Token: 0x0600147C RID: 5244 RVA: 0x0006A118 File Offset: 0x00068318
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event Action<AppSession, NetHandle, string> AcceptString;

		/// <summary>
		/// 当接收到字节数据的时候,触发此事件
		/// </summary>
		// Token: 0x14000029 RID: 41
		// (add) Token: 0x0600147D RID: 5245 RVA: 0x0006A150 File Offset: 0x00068350
		// (remove) Token: 0x0600147E RID: 5246 RVA: 0x0006A188 File Offset: 0x00068388
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event Action<AppSession, NetHandle, byte[]> AcceptByte;

		/// <summary>
		/// 当接收到了新的请求的时候执行的操作
		/// </summary>
		/// <param name="socket">异步对象</param>
		/// <param name="endPoint">终结点</param>
		// Token: 0x0600147F RID: 5247 RVA: 0x0006A1C0 File Offset: 0x000683C0
		protected override void ThreadPoolLogin(Socket socket, IPEndPoint endPoint)
		{
			bool flag = this.appSessions.Count > this.ConnectMax;
			if (flag)
			{
				if (socket != null)
				{
					socket.Close();
				}
				ILogNet logNet = base.LogNet;
				if (logNet != null)
				{
					logNet.WriteWarn(this.ToString(), StringResources.Language.NetClientFull);
				}
			}
			else
			{
				OperateResult<int, string> operateResult = base.ReceiveStringContentFromSocket(socket, 30000);
				bool flag2 = !operateResult.IsSuccess;
				if (!flag2)
				{
					AppSession appSession = new AppSession
					{
						WorkSocket = socket,
						LoginAlias = operateResult.Content2
					};
					appSession.IpEndPoint = endPoint;
					appSession.IpAddress = ((endPoint == null) ? string.Empty : endPoint.Address.ToString());
					bool flag3 = operateResult.Content1 == 1;
					if (flag3)
					{
						appSession.ClientType = "Windows";
					}
					else
					{
						bool flag4 = operateResult.Content1 == 2;
						if (flag4)
						{
							appSession.ClientType = "Android";
						}
					}
					try
					{
						appSession.WorkSocket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, new AsyncCallback(this.ReceiveCallback), appSession);
						this.TcpStateUpLine(appSession);
						Thread.Sleep(20);
					}
					catch (Exception ex)
					{
						Socket workSocket = appSession.WorkSocket;
						if (workSocket != null)
						{
							workSocket.Close();
						}
						ILogNet logNet2 = base.LogNet;
						if (logNet2 != null)
						{
							logNet2.WriteException(this.ToString(), StringResources.Language.NetClientLoginFailed, ex);
						}
					}
				}
			}
		}

		// Token: 0x06001480 RID: 5248 RVA: 0x0006A334 File Offset: 0x00068534
		[DebuggerStepThrough]
		private void ReceiveCallback(IAsyncResult ar)
		{
			NetComplexServer.<ReceiveCallback>d__31 <ReceiveCallback>d__ = new NetComplexServer.<ReceiveCallback>d__31();
			<ReceiveCallback>d__.<>t__builder = AsyncVoidMethodBuilder.Create();
			<ReceiveCallback>d__.<>4__this = this;
			<ReceiveCallback>d__.ar = ar;
			<ReceiveCallback>d__.<>1__state = -1;
			<ReceiveCallback>d__.<>t__builder.Start<NetComplexServer.<ReceiveCallback>d__31>(ref <ReceiveCallback>d__);
		}

		/// <summary>
		/// 服务器端用于数据发送文本的方法
		/// </summary>
		/// <param name="session">数据发送对象</param>
		/// <param name="customer">用户自定义的数据对象，如不需要，赋值为0</param>
		/// <param name="str">发送的文本</param>
		// Token: 0x06001481 RID: 5249 RVA: 0x0006A374 File Offset: 0x00068574
		public void Send(AppSession session, NetHandle customer, string str)
		{
			base.Send(session.WorkSocket, HslProtocol.CommandBytes(customer, base.Token, str));
		}

		/// <summary>
		/// 服务器端用于发送字节的方法
		/// </summary>
		/// <param name="session">数据发送对象</param>
		/// <param name="customer">用户自定义的数据对象，如不需要，赋值为0</param>
		/// <param name="bytes">实际发送的数据</param>
		// Token: 0x06001482 RID: 5250 RVA: 0x0006A395 File Offset: 0x00068595
		public void Send(AppSession session, NetHandle customer, byte[] bytes)
		{
			base.Send(session.WorkSocket, HslProtocol.CommandBytes(customer, base.Token, bytes));
		}

		/// <summary>
		/// 服务端用于发送所有数据到所有的客户端
		/// </summary>
		/// <param name="customer">用户自定义的命令头</param>
		/// <param name="str">需要传送的实际的数据</param>
		// Token: 0x06001483 RID: 5251 RVA: 0x0006A3B8 File Offset: 0x000685B8
		public void SendAllClients(NetHandle customer, string str)
		{
			object obj = this.lockSessions;
			lock (obj)
			{
				for (int i = 0; i < this.appSessions.Count; i++)
				{
					this.Send(this.appSessions[i], customer, str);
				}
			}
		}

		/// <summary>
		/// 服务端用于发送所有数据到所有的客户端
		/// </summary>
		/// <param name="customer">用户自定义的命令头</param>
		/// <param name="data">需要群发客户端的字节数据</param>
		// Token: 0x06001484 RID: 5252 RVA: 0x0006A428 File Offset: 0x00068628
		public void SendAllClients(NetHandle customer, byte[] data)
		{
			object obj = this.lockSessions;
			lock (obj)
			{
				for (int i = 0; i < this.appSessions.Count; i++)
				{
					this.Send(this.appSessions[i], customer, data);
				}
			}
		}

		/// <summary>
		/// 根据客户端设置的别名进行发送消息
		/// </summary>
		/// <param name="Alias">客户端上线的别名</param>
		/// <param name="customer">用户自定义的命令头</param>
		/// <param name="str">需要传送的实际的数据</param>
		// Token: 0x06001485 RID: 5253 RVA: 0x0006A498 File Offset: 0x00068698
		public void SendClientByAlias(string Alias, NetHandle customer, string str)
		{
			object obj = this.lockSessions;
			lock (obj)
			{
				for (int i = 0; i < this.appSessions.Count; i++)
				{
					bool flag2 = this.appSessions[i].LoginAlias == Alias;
					if (flag2)
					{
						this.Send(this.appSessions[i], customer, str);
					}
				}
			}
		}

		/// <summary>
		/// 根据客户端设置的别名进行发送消息
		/// </summary>
		/// <param name="Alias">客户端上线的别名</param>
		/// <param name="customer">用户自定义的命令头</param>
		/// <param name="data">需要传送的实际的数据</param>
		// Token: 0x06001486 RID: 5254 RVA: 0x0006A528 File Offset: 0x00068728
		public void SendClientByAlias(string Alias, NetHandle customer, byte[] data)
		{
			object obj = this.lockSessions;
			lock (obj)
			{
				for (int i = 0; i < this.appSessions.Count; i++)
				{
					bool flag2 = this.appSessions[i].LoginAlias == Alias;
					if (flag2)
					{
						this.Send(this.appSessions[i], customer, data);
					}
				}
			}
		}

		// Token: 0x170004E9 RID: 1257
		// (get) Token: 0x06001487 RID: 5255 RVA: 0x0006A5B8 File Offset: 0x000687B8
		// (set) Token: 0x06001488 RID: 5256 RVA: 0x0006A5C0 File Offset: 0x000687C0
		private Thread Thread_heart_check { get; set; } = null;

		// Token: 0x06001489 RID: 5257 RVA: 0x0006A5CC File Offset: 0x000687CC
		private void ThreadHeartCheck()
		{
			bool flag4;
			do
			{
				Thread.Sleep(2000);
				try
				{
					AppSession[] array = null;
					object obj = this.lockSessions;
					lock (obj)
					{
						array = this.appSessions.ToArray();
					}
					for (int i = array.Length - 1; i >= 0; i--)
					{
						bool flag2 = array[i] == null;
						if (!flag2)
						{
							bool flag3 = (DateTime.Now - array[i].HeartTime).TotalSeconds > 30.0;
							if (flag3)
							{
								ILogNet logNet = base.LogNet;
								if (logNet != null)
								{
									logNet.WriteWarn(this.ToString(), StringResources.Language.NetHeartCheckTimeout + array[i].IpAddress.ToString());
								}
								this.TcpStateDownLine(array[i], false, false);
							}
						}
					}
				}
				catch (Exception ex)
				{
					ILogNet logNet2 = base.LogNet;
					if (logNet2 != null)
					{
						logNet2.WriteException(this.ToString(), StringResources.Language.NetHeartCheckFailed, ex);
					}
				}
				flag4 = !base.IsStarted;
			}
			while (!flag4);
		}

		/// <inheritdoc />
		// Token: 0x0600148A RID: 5258 RVA: 0x0006A71C File Offset: 0x0006891C
		public override string ToString()
		{
			return string.Format("NetComplexServer[{0}]", base.Port);
		}

		// Token: 0x040004DF RID: 1247
		private int connectMaxClient = 10000;

		// Token: 0x040004E0 RID: 1248
		private readonly List<AppSession> appSessions = null;

		// Token: 0x040004E1 RID: 1249
		private readonly object lockSessions = null;
	}
}
